package com.strongbj.iot.devices.newlight.response.handle;

import java.net.InetSocketAddress;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.strongbj.core.message.IMessageHandle;
import com.strongbj.core.util.ByteUtil;
import com.strongbj.core.util.ContextUtils;
import com.strongbj.iot.devices.newlight.entity.Reader;
import com.strongbj.iot.devices.newlight.entity.T;
import com.strongbj.iot.devices.newlight.message.NewLightOSMessageFactory;
import com.strongbj.iot.devices.newlight.message.NewLightReaderMessage;
import com.strongbj.iot.devices.newlight.response.common.HandleTimeStamp;
import com.strongbj.iot.devices.newlight.response.vo.ReaderInfoOfHeartbeat;
import com.strongbj.iot.devices.newlight.service.ReaderService;

import cn.hutool.core.lang.UUID;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;

/**
 * 0x37，读写器心跳
 * 
 * @author lei_w
 *
 */
public class HeartbeatResponseHandle implements IMessageHandle<NewLightReaderMessage, Object> {
	private static Logger logger = LogManager.getLogger(HeartbeatResponseHandle.class.getName());
	private ReaderService readerService = (ReaderService) ContextUtils.getBean("readerService");
	private NewLightOSMessageFactory newLightOSMessageFactory = (NewLightOSMessageFactory) ContextUtils
			.getBean("newLightOSMessageFactory");
	private static Map<String, ReaderInfoOfHeartbeat> readerMap = new ConcurrentHashMap<>(); // 记录心跳采集的设备信息
	private String currentReaderCode;

	@Override
	public boolean isHandle(NewLightReaderMessage t) {
		if (Integer.valueOf("37", 16).byteValue() == t.getType()) {
			return true;
		} else {
			return false;
		}
	}

	@Override
	public Object handle(ChannelHandlerContext ctx, NewLightReaderMessage t) {
		System.out.println("返回报文--" + ByteUtil.byteArrToHexString(t.getBody()));
		String hostNumber = ByteUtil.byteArrToHexString(t.getAddress()); // reader 地址码
		
		this.saveReaderInfoToCache(hostNumber, t); // 将从心跳获取的读写器信息保存到内存中
		this.sendHeartbeatReturnCommand(hostNumber, ctx, t); // 发送心跳反馈信息
		
		String timeStamp = ByteUtil.byteArrToHexString(t.getTime()); // 时间戳

		short tagNum = ByteUtil.byteArrToShort(t.getBody()); // 读写器标签个数
		String maxShortAddress = ByteUtil.byteArrToHexString(t.getBody(), 2, 2); // 内部标签最大短地址
		String latelyInventoryRefreshTime = ByteUtil.byteArrToHexString(t.getBody(), 4, 4); // 最近一次盘点刷新时间
		String latelyInventoryTimeConsuming = ByteUtil.byteArrToHexString(t.getBody(), 8, 4); // 最近一次盘点耗时

		String log = "\r\n===================================================" + "\r\n读写器心跳：" + "\r\nREADER地址码： "
				+ hostNumber + "\r\n读写器标签个数：" + tagNum + "\r\n内部标签最大短地址：" + maxShortAddress + "\r\n最近一次盘点刷新时间："
				+ HandleTimeStamp.handle(latelyInventoryRefreshTime) + "\r\n最近一次盘点耗时："
				+ Long.valueOf(latelyInventoryTimeConsuming, 16) + "\r\n时间戳：" + HandleTimeStamp.handle(timeStamp);
		logger.info(log);

		try {
			InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
			String ip = insocket.getAddress().getHostAddress();
			String deviceCode = ByteUtil.bytesToAddress(t.getAddress());
			this.saveReaderInfoToDB(deviceCode, ip); // 更新数据库
		} catch (Exception e) {
			logger.error("从心跳处理类中更新设备信息出错", e);
		}
		
		return null;
	}

	/**
	 * 保存Reader信息到数据库
	 * @param deviceCode
	 * @param ip
	 */
	private void saveReaderInfoToDB(String deviceCode, String ip) {
		logger.info("要保存的设备信息 deviceCode={} ip={} ", deviceCode,ip);
		QueryWrapper<Reader> wrapper = new QueryWrapper<Reader>();
		wrapper.eq("code_", deviceCode);
		Reader reader = readerService.getOne(wrapper);
		if (reader == null) {
			reader = new Reader();
			reader.setIp(UUID.randomUUID().toString());
			logger.info("设备未查到============= ");
		}
		reader.setCode(deviceCode);
		reader.setIp(ip);
		reader.setLastHeartbeatTime(new Date());
		try {
			logger.info("更新后保存的设备信息 JSON={} ", JSON.toJSONString(reader));
		}catch(Exception e) {}
		readerService.saveOrUpdate(reader);
	}

	/**
	 * 保存读写器数据到缓存
	 * 
	 * @param hostNumber
	 * @param t
	 */
	private void saveReaderInfoToCache(String hostNumber, NewLightReaderMessage t) {
		this.currentReaderCode = hostNumber;
		ReaderInfoOfHeartbeat readerInfo = null;
		if (readerMap.containsKey(hostNumber)) {
			readerInfo = readerMap.get(hostNumber);
		} else {
			readerInfo = new ReaderInfoOfHeartbeat();
			readerMap.put(hostNumber, readerInfo);
		}

		readerInfo.setReaderCode(t.getAddress());
		byte[] tagCount = new byte[2];
		System.arraycopy(t.getBody(), 0, tagCount, 0, 2);
		readerInfo.setTagCount(tagCount);
		byte[] time = new byte[4];
		System.arraycopy(t.getBody(), 8, time, 0, 4);
		readerInfo.setLatelyInventoryTimeConsuming(time);
	}

	/**
	 * 发送心跳返回命令
	 * 
	 * @param hostNumber
	 * @param ctx
	 */
	private void sendHeartbeatReturnCommand(String hostNumber, ChannelHandlerContext ctx, NewLightReaderMessage t) {
		byte[] datas = new byte[1 + (9 * readerMap.size())];
		datas[0] = Integer.valueOf(readerMap.size()).byteValue();
		Iterator<Map.Entry<String, ReaderInfoOfHeartbeat>> it = readerMap.entrySet().iterator();
		int index = 1;
		while (it.hasNext() && index <= (readerMap.size() - 1) * 9+1) {
			Map.Entry<String, ReaderInfoOfHeartbeat> entry = it.next();
			System.arraycopy(entry.getValue().getReaderCode(), 0, datas, index, 3); // 拷贝读写器编码
			index += 3;
			System.arraycopy(entry.getValue().getTagCount(), 0, datas, index, 2); // 拷贝读写器绑定的标签数量
			index += 2;
			System.arraycopy(entry.getValue().getLatelyInventoryTimeConsuming(), 0, datas, index, 4); // 拷贝最后一次盘点耗时
			index += 4;
		}
		byte[] req = newLightOSMessageFactory.createNewLightOSMessage(t.getAddress(), (byte) 0x37, datas,
				T.getTimeStamp());
		Channel channel = ctx.channel();
		ByteBuf bs = Unpooled.copiedBuffer(req);
		ChannelFuture cf = channel.writeAndFlush(bs);
		cf.addListener(new ChannelFutureListener() {
			@Override
			public void operationComplete(ChannelFuture future) throws Exception {
				if (future.isSuccess()) {
					logger.info("发送心跳反馈命令成功 设备编号:{} 发送命令:{}", hostNumber,ByteUtil.byteArrToHexString(req, true));
				} else {
					logger.debug("发送心跳反馈命令失败 设备编号:{} 发送命令:{}", hostNumber,ByteUtil.byteArrToHexString(req, true));
				}
			}
		});
	}

	@Override
	public void destory() {
		// 从内存中清除读写器信息
		if (this.currentReaderCode != null && readerMap.containsKey(this.currentReaderCode)) {
			readerMap.remove(this.currentReaderCode);
		}
	}
}
